<?php
/**
 * 公用方法
 */

if (!function_exists('friendlyDate')) {
    /**
     * 友好的时间显示
     *
     * @param int $sTime 待显示的时间
     * @param string $type 类型. normal | mohu | full | ymd | other
     * @param string $alt 已失效
     * @return string
     */
    function friendlyDate($sTime, $type = 'normal', $alt = 'false')
    {
        if (!$sTime)
            return '';

        //sTime=源时间，cTime=当前时间，dTime=时间差
        $cTime = time();
        $dTime = $cTime - $sTime;
        $dDay = intval(date("z", $cTime)) - intval(date("z", $sTime));
        $dYear = intval(date("Y", $cTime)) - intval(date("Y", $sTime));
        //normal：n秒前，n分钟前，n小时前，日期
        if ($type == 'normal') {
            if ($dTime < 60) {
                if ($dTime < 10) {
                    return '刚刚';
                } else {
                    return intval(floor($dTime / 10) * 10) . "秒前";
                }
            } elseif ($dTime < 3600) {
                return intval($dTime / 60) . "分钟前";
            } elseif ($dYear == 0 && $dDay == 0) {
                return '今天' . date('H:i', $sTime);
            } elseif ($dYear == 0) {
                return date("m月d日 H:i", $sTime);
            } else {
                return date("Y-m-d H:i", $sTime);
            }
        } elseif ($type == 'mohu') {
            if ($dTime < 60) {
                return $dTime . "秒前";
            } elseif ($dTime < 3600) {
                return intval($dTime / 60) . "分钟前";
            } elseif ($dTime >= 3600 && $dDay == 0) {
                return intval($dTime / 3600) . "小时前";
            } elseif ($dDay > 0 && $dDay <= 7) {
                return intval($dDay) . "天前";
            } elseif ($dDay > 7 && $dDay <= 30) {
                return intval($dDay / 7) . '周前';
            } elseif ($dDay > 30) {
                return intval($dDay / 30) . '个月前';
            }
        } elseif ($type == 'full') {
            return date("Y-m-d , H:i:s", $sTime);
        } elseif ($type == 'ymd') {
            return date("Y-m-d", $sTime);
        } else {
            if ($dTime < 60) {
                return $dTime . "秒前";
            } elseif ($dTime < 3600) {
                return intval($dTime / 60) . "分钟前";
            } elseif ($dTime >= 3600 && $dDay == 0) {
                return intval($dTime / 3600) . "小时前";
            } elseif ($dYear == 0) {
                return date("Y-m-d H:i:s", $sTime);
            } else {
                return date("Y-m-d H:i:s", $sTime);
            }
        }
    }
}


if (!function_exists('getRequest')) {
    /**
     * @param string $url
     * @param array $header
     * @return mixed
     */
    function getRequest($url, $header = [])
    {
        //初始化
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        // 执行后不直接打印出来
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        // 不从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        // 请求头，可以传数组
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        //执行并获取HTML文档内容
        $output = curl_exec($ch);

        //释放curl句柄
        curl_close($ch);

        return $output;
    }
}

if (!function_exists('postRequest')) {
    /**
     * @param string $url
     * @param array $post_data
     * @param array $header
     * @return mixed
     */
    function postRequest($url, $post_data, $header = [])
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        // 执行后不直接打印出来
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        // 设置请求方式为post
        curl_setopt($ch, CURLOPT_POST, true);
        // post的变量
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        // 请求头，可以传数组
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        // 不从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $output = curl_exec($ch);

        curl_close($ch);
        return $output;
    }
}

if (!function_exists('httpRequest')) {
    /**
     * 发送请求集合
     * @param $url
     * @param $method
     * @param array $postData
     * @param array $headers
     * @param bool $ssl
     * @param array $ssl_config
     * @param bool $debug
     * @return mixed
     */
    function httpRequest($url, $method, $postData = [], $headers = [], $ssl = false, $ssl_config = [], $debug = false)
    {
        // 将方法统一换成大写
        $method = strtoupper($method);
        // 初始化
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
        // 在发起连接前等待的时间，如果设置为0，则无限等待
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 60);
        // 设置CURL允许执行的最长秒数
        curl_setopt($curl, CURLOPT_TIMEOUT, 7);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

        switch ($method) {
            case "POST":
                curl_setopt($curl, CURLOPT_POST, true);
                if (!empty($postData)) {
                    $tmpdatastr = is_array($postData) ? http_build_query($postData) : $postData;
                    curl_setopt($curl, CURLOPT_POSTFIELDS, $tmpdatastr);
                }
                break;
            default:
                curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
                break;
        }

        curl_setopt($curl, CURLOPT_URL, $url);

        if ($ssl == true) {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, TRUE);
            // 严格校验
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
            // 设置证书
            curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');

            $certPemPath = realpath($ssl_config["certPemPath"]);
            $keyPemPath = realpath($ssl_config["keyPemPath"]);

            curl_setopt($curl, CURLOPT_SSLCERT, $certPemPath);
            curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($curl, CURLOPT_SSLKEY, $keyPemPath);
        }


        // 启用时会将头文件的信息作为数据流输出
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
        // 指定最多的HTTP重定向的数量，这个选项是和CURLOPT_FOLLOWLOCATION一起使用的
        curl_setopt($curl, CURLOPT_MAXREDIRS, 2);

        // 添加请求头部
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLINFO_HEADER_OUT, true);
        // COOKIE带过去
//        curl_setopt($curl, CURLOPT_COOKIE, $Cookiestr);
        $response = curl_exec($curl);
        $requestInfo = curl_getinfo($curl);
        $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $response_error = curl_error($curl);


        // 开启调试模式就返回 curl 的结果
        if ($debug) {
            echo "=====post data======\r\n";
            dump($postData);
            echo "=====info===== \r\n";
            dump($requestInfo);
            echo "=====response=====\r\n";
            dump($response);
            echo "=====http_code=====\r\n";
            dump($http_code);
            echo "=====http_error=====\r\n";
            dump($response_error);

            dump(curl_getinfo($curl, CURLINFO_HEADER_OUT));
        }
        curl_close($curl);
        return $response;
    }
}


if (!function_exists('checkFilePath')) {
    /**
     * 检测文件是否存在并且创建文件
     * @param $path
     * @return bool
     */
    function checkFilePath($path)
    {
        if (!is_dir($path)) {
            if (mkdir($path, 0777, true)) {
                chmod($path, 0777);
                if (!is_writable($path)) {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }
}

if (!function_exists('getTree')) {
    /**
     * 生成结构树
     * @param $node_info
     * @return array|bool
     */
    function getTree($node_info)
    {
        $level_info = [];
        $level_tree = [];
        if (!empty($node_info)) {
            // 先将键值对上
            foreach ($node_info as $value) {
                $level_info[$value['id']] = $value;
                $level_info[$value['id']]['sub_item'] = [];
            }
            // 编辑菜单
            foreach ($level_info as $key => $item) {
                // 如果是根菜单就直接添加 数组的地址，
                // 之后这个数组里面填加的内容都会同步进去
                if ($item["parent_id"] == 0 || empty($level_info[$item['parent_id']])) {
                    $level_tree[] = &$level_info[$key];
                } else {
                    $level_info[$item['parent_id']]['sub_item'][] = &$level_info[$key];
                }
            }
        }
        return $level_tree;
    }
}

if (!function_exists('objToArray')) {
    /**
     * 将对象转换成数组
     * @param $obj
     * @return mixed
     */
    function objToArray($obj)
    {
        return json_decode(json_encode($obj, JSON_UNESCAPED_UNICODE), true);
    }
}

if (!function_exists('arrayToObj')) {
    /**
     * 将对象转换成数组
     * @param $arr
     * @return mixed
     */
    function arrayToObj($arr)
    {
        if (gettype($arr) != 'array') {
            return;
        }
        return json_decode(json_encode($arr, JSON_UNESCAPED_UNICODE));
    }
}

if (!function_exists('structureTree')) {
    /**
     * 生成结构树
     * @param $list
     * @param array $combination
     * @param int $deep
     * @param int $is_final
     * @return array
     */
    function structureTree($list, $combination = [], $deep = 0, $is_final = 0)
    {
        // 查看处理的数组有多少个
        $count = count($list);
        foreach ($list as $key => $item) {
            // 当前的位置（1开头）
            $current_num = $key + 1;

            $level_name = '';
            if (!empty($deep)) {
                for ($i = 0; $i < $deep; $i++) {
                    // 判断是否为最后一层
                    if ($i == $deep - 1) {
                        // 判断是否为最后一层的最后一个
                        if ($current_num == $count) {
                            $level_name .= '└&nbsp;';
                        } else {
                            $level_name .= '├&nbsp;';
                        }
                    } else {
                        // 如果是第一层的最后一个 的子元素 的 第一个
                        if ($is_final == 1 && $i == 0) {
                            $level_name .= '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
                        } else {
                            $level_name .= '│&nbsp;';
                        }
                    }
                }
            }

            $item['level_name'] = $level_name . $item['name'];

            // 删除掉 sub_menu 键的元素
            $combination[] = array_diff_key($item, ['sub_menu' => 1]);
            if (!empty($item['sub_item'])) {
                // 判断是否第一层的最后一个
                if ($deep == 1 && $current_num == $count) {
                    $is_final = 1;
                }
                $deep_tmp = $deep;
                $combination = structureTree($item['sub_item'], $combination, $deep_tmp + 1, $is_final);
            }
        }
        return $combination;
    }
}

if (!function_exists('exportCsv')) {
    /**
     * 导出cvs文件
     * @param $filePath
     * @param $thead
     * @param $tbody
     */
    function exportCsv($filePath, $thead, $tbody)
    {
        ini_set('max_execution_time', 300);
        ini_set('memory_limit', '1024M');

        // 检测并创建文件
        checkFilePath(dirname($filePath));
        $index = 0;
        $fp = fopen($filePath, 'w'); //生成临时文件
        foreach ($thead as $key => $val) {
            $thead[$key] = iconv('utf-8', 'gbk', $val);
        }
        fputcsv($fp, $thead);

        // 处理导出数据
        foreach ($tbody as $key => &$val) {
            foreach ($val as $k => $v) {
                $val[$k] = iconv('utf-8', 'gbk', $v) . "\t";
                // 每次写入10000条数据清除内存
                if ($index == 10000) {
                    $index = 0;
                    ob_flush();//清除内存
                    flush();
                }
                $index++;
            }
            fputcsv($fp, $val);
        }
        ob_flush();
        // 关闭句柄
        fclose($fp);
        header("Cache-Control: max-age=0");
        header("Content-type:application/vnd.ms-excel;charset=UTF-8");
        header("Content-Description: File Transfer");
        header('Content-disposition: attachment; filename=' . basename($filePath));
        header("Content-Type: text/csv");
        header("Content-Transfer-Encoding: binary");
        header('Content-Length: ' . filesize($filePath));
        // 输出文件
        @readfile($filePath);
        // 删除压缩包临时文件
        unlink($filePath);
//        echo $filePath;
        return;
    }
}

if (!function_exists('priceFormat')) {
    /**
     * 格式化金钱，最后一位四舍五入
     * @param $price
     * @return string
     */
    function priceFormat($price)
    {
        return number_format($price, 2, ".", "");
    }
}

if (!function_exists('getDateScope')) {
    /**
     * 获取最近七天所有日期
     * @param string $time 时间戳
     * @param string $format 日期格式
     * @param int $number 数量
     * @return array
     */
    function getDateScope($time = '', $format = 'Y-m-d', $number = 7)
    {
        $time = $time != '' ? $time : time();
        //组合数据
        $date = [];
        for ($i = $number; $i >= 0; $i--) {
            $date[] = date($format, strtotime('-' . $i . ' days', $time));
        }
        return $date;
    }
}


if (!function_exists('xml2array')) {
    /**
     * 将XML格式字符串转换为array
     * @param string $str XML格式字符串
     * @return array
     * @throws \Exception
     */
    function xml2array($str)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);

        $xml = simplexml_load_string($str, 'SimpleXMLElement', LIBXML_NOCDATA);
        $json = json_encode($xml);
        $result = array();
        // value，一个字段多次出现，结果中的value是数组
        $bad_result = json_decode($json, TRUE);

        if (!empty($bad_result)) {
            foreach ($bad_result as $k => $v) {
                if (is_array($v)) {
                    if (count($v) == 0) {
                        $result[$k] = '';
                    } else if (count($v) == 1) {
//                    $result[$k] = $v[0];
                        $result[$k] = current($v);
                    } else {
                        throw new \Exception('Duplicate elements in XML. ' . $str);
                    }
                } else {
                    $result[$k] = $v;
                }
            }
        }
        return $result;
    }
}

if (!function_exists('array2xml')) {
    /**
     * 将array转换为XML格式的字符串
     * @param array $data
     * @param string $header_element
     * @return string
     * @throws \Exception
     */
    function array2xml($data, $header_element = "<xml/>")
    {
        $xml = simplexml_load_string($header_element);
        createXml($data, $xml);
        return $xml->saveXML();
    }
}

if (!function_exists('createXml')) {
    /**
     * @param $data
     * @param $xml
     */
    function createXml($data, $xml)
    {
        foreach ($data as $k => $v) {
            if (is_array($v)) {
                $x = $xml->addChild($k);
                createXml($v, $x);
            } else {
                $xml->addChild($k, $v);
            }
        }
    }
}


if (!function_exists('xmlParser')) {
    /**
     * 判断是否为xml 格式
     * @param $str
     * @return bool
     */
    function xmlParser($str)
    {
        $xml_parser = xml_parser_create();
        if (!xml_parse($xml_parser, $str, true)) {
            xml_parser_free($xml_parser);
            return false;
        } else {
            return true;
        }
    }
}

if (!function_exists('arrayToXml2')) {
    /**
     * 数组转换成xml 标签，不带xml 头部
     * @param $data
     * @param bool $eIsArray
     * @param $xmlObj
     * @return string
     */
    function arrayToXml2($data, $eIsArray = FALSE, $xmlObj = "")
    {
        if (!empty($xmlObj)) {
            $xml = $xmlObj;
        } else {
            $xml = new \XmlWriter();
        }

        if (!$eIsArray) {
            $xml->openMemory();
        }

        foreach ($data as $key => $value) {
            if (is_array($value)) {
                $xml->startElement($key);
                arrayToXml2($value, TRUE, $xml);
                $xml->endElement();
                continue;
            }
            $xml->writeElement($key, $value);
        }

        if (!$eIsArray) {
            $xml->endElement();
            return $xml->outputMemory(true);
        }
    }
}

if (!function_exists('charset')) {
    /**
     * 更改字符编码
     * @param $param
     * @param $target
     * @param $source
     * @return null|string|string[]
     */
    function charset($param, $target, $source)
    {
        if (strcasecmp($source, $target) != 0) {
            $param = mb_convert_encoding($param, $target, $source);
        }
        return $param;
    }
}

if (!function_exists('array2GBK')) {
    /**
     * 数组编码成GBK
     * @param $param
     * @return array
     */
    function array2GBK($param)
    {
        $param = array_map(function ($value) {
            return iconv('utf-8', 'gbk', $value);
        }, $param);

        return $param;
    }
}


if (!function_exists('array2UTF8')) {
    /**
     * 数组编码成UTF8
     * @param $param
     * @return array
     */
    function array2UTF8($param)
    {
        $param = array_map(function ($value) {
            return iconv('utf-8', 'gbk', $value);
        }, $param);

        return $param;
    }
}

if (!function_exists('checkEmpty')) {
    /**
     * 检测是否为空
     * @param $value
     * @return bool
     */
    function checkEmpty($value)
    {
        if (!isset($value)) {
            return true;
        }
        if ($value === null) {
            return true;
        }
        if (trim($value) === "") {
            return true;
        }
        return false;
    }
}

if (!function_exists('getSignContent')) {
    /**
     * 排序并且拼接字符串
     * @param $params
     * @return string
     */
    function getSignContent($params)
    {
        ksort($params);
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === checkEmpty($v) && "@" != substr($v, 0, 1)) {
                $v = charset($v, $params["charset"], $params["charset"]);
                if ($i == 0) {
                    $stringToBeSigned .= "{$k}={$v}";
                } else {
                    $stringToBeSigned .= "&{$k}={$v}";
                }
                $i++;
            }
        }
        unset($k, $v);
        return $stringToBeSigned;
    }
}

if (!function_exists('sortAndCombine')) {
    /**
     * 排序数组并拼接成字符串
     * @param $data
     * @return string
     */
    function sortAndCombine($data)
    {
        $combineStr = '';
        ksort($data);
        // 处理数据
        foreach ($data as $key => $value) {
            $combineStr .= "{$key}={$value}&";
        }
        $combineStr = rtrim($combineStr, "&");
        return $combineStr;
    }
}

if (!function_exists('nonceStr')) {
    /**
     * 生成随机数
     * @return string
     */
    function nonceStr()
    {
        return sprintf('%04x%04x%04x%04x%04x%04x%04x%04x',
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
            mt_rand(0, 0xffff),
            mt_rand(0, 0x0fff) | 0x4000,
            mt_rand(0, 0x3fff) | 0x8000,
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
        );
    }
}

if (!function_exists('wxSignature')) {
    /**
     * 生成签名（只支持MD5）
     * @param $data
     * @param $key
     * @return string
     */
    function wxSignature($data, $key)
    {
        $combineStr = '';
        // 去所有的键名
        $keys = array_keys($data);
        // 排序
        asort($keys);
        // 处理数据
        foreach ($keys as $k) {
            $v = $data[$k];
            if ($k == "sign") {
                continue;
            } else if ((is_string($v) && strlen($v) > 0) || is_numeric($v)) {
                $combineStr = "${combineStr}${k}=${v}&";
            } else if (is_string($v) && strlen($v) == 0) {
                continue;
            }
        }
        $combineStr = "${combineStr}key=$key";
        // 返回签名
        return strtoupper(md5($combineStr));
    }
}

if (!function_exists('privateSign')) {
    /**
     * 私钥
     * @param $data
     * @param $priKey
     * @param string $signType
     * @param string $encodeType
     * @return string
     */
    function privateSign($data, $priKey, $signType = "RSA", $encodeType = "SHA")
    {
        // 完善支付密钥参数
        $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($priKey, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";
        ($res) or die('您使用的私钥格式错误，请检查 RSA 私钥配置');


        if ("RSA2" == $signType) {
            if ($encodeType == "SHA") {
                // OPENSSL_ALGO_SHA256 是 php5.4.8 以上版本才支持
                openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
            } else if ($encodeType == "MD5") {
                //MD5WithRSA私钥加密
                openssl_sign($data, $sign, $res, OPENSSL_ALGO_MD5);
            }
        } else {
            openssl_sign($data, $sign, $res);
        }

        $sign = base64_encode($sign);
        return $sign;
    }
}

if (!function_exists('publicSign')) {

    /**
     * 公钥信息
     * @param $data
     * @param $priKey
     * @param string $encodeType
     * @return int
     */
    function publicSign($data, $priKey, $encodeType = "SHA")
    {
        // 完善支付密钥参数
        $res = "-----BEGIN PUBLIC KEY-----\n" .
            wordwrap($priKey, 64, "\n", true) .
            "\n-----END PUBLIC KEY-----";
        ($res) or die('您使用的公钥格式错误，请检查 公钥配置');


        $pubkey = openssl_pkey_get_public($res);

        if ($encodeType == "SHA") {
            // OPENSSL_ALGO_SHA256 是 php5.4.8 以上版本才支持
            $sign = openssl_verify($data, base64_decode($pubkey), $pubkey, OPENSSL_ALGO_SHA256);
        } else if ($encodeType == "MD5") {
            // MD5WithRSA解密
            $sign = openssl_verify($data, base64_decode($pubkey), $pubkey, OPENSSL_ALGO_MD5);
        }

        return $sign;
    }
}